(* open IntInf; *)

fun read file =
    let
        val inStream = TextIO.openIn file
    in
        (* TextIO.inputAll returns a TextIO.vector, which is a string. *)
        TextIO.inputAll inStream
    end;

val newline_tokenizer = String.tokens (fn c => c = #"\n");


fun sum_lists (nil, nil) = []
  | sum_lists (nil, l2) = []
  | sum_lists (l1, nil) = []
  | sum_lists (alst as (a::arest), blst as (b::brest)) =
    (a + b)::sum_lists(arest, brest);


fun string_to_ints str =
    map (fn c =>
            case c of
                #"1" => 1
              | #"0" => 0
              | _ => raise Fail "unrecognized bit value")
        (String.explode str);


fun invert 0 = 1
  | invert 1 = 0
  | invert _ = raise Fail "unrecognized bit value";
fun invert_list lst = map invert lst;


fun make_list (0, _) = []
  | make_list (len, fill) =
    fill :: make_list (len - 1, fill);


fun calc_rates lines =
    let
        fun iter (nil, sum, count) = (sum, count)
          | iter (remaining_lines as (line::rest_lines), sum, count) =
            let
                val ints = string_to_ints line;
                val acc = sum_lists (sum, ints);
            in
                iter (rest_lines, acc, count + 1)
            end;
    in
        let
            val zero = make_list (length (String.explode (hd lines)), 0);
            val (sums, len) = iter (lines, zero, 0);
            val gamma_rate_bits =
                map (fn sum => if sum > (len div 2)
                               then 1
                               else 0)
                    sums;
            val epsilon_bits = invert_list gamma_rate_bits;
        in
            (gamma_rate_bits, epsilon_bits)
        end
    end;


fun int_expt (0, _) = 0
  | int_expt (1, _) = 1
  | int_expt (base, 0) = 1
  | int_expt (base, 1) = base
  | int_expt (base, exponent) =
    base * int_expt (base, exponent - 1);

fun bit_to_decimal (bit, ind) =
    bit * int_expt (2, ind);

fun bits_to_decimal bits =
    List.foldli (fn (ind, bit, acc) =>
                    acc + bit_to_decimal (bit, ind))
                0
                (rev bits);



val str = read "input";
val lines = newline_tokenizer str;
val (gamma_rate, epsilon_rate) = calc_rates lines;
val solution = (bits_to_decimal gamma_rate) * (bits_to_decimal epsilon_rate);
solution;
